package org.example.lys.utils;

import java.util.*;

/**
 * 敏感词汇过滤类
 * 包含三个主要方法
 * 1.isContaintSensitiveWord，判断输入的内容是不是包含敏感词汇
 * 2.getSensitiveWord,获取输入内容的敏感词
 * 3.replaceSensitiveWord,替换敏感词汇字符
 */
public class SensitiveWordFilter {

    //敏感词汇map
    private HashMap sensitiveWordMap;
    //最小匹配规则
    //一旦匹配到，不继续匹配，直接返回
    private static int minMatchTYpe = 1;
    //最大匹配规则
    //匹配所有的
    private static int maxMatchType = 2;
    //关键词汇集合
    public List<String> list = new ArrayList<>();


    /**
     * 构造函数，初始化敏感词汇库
     *
     * @param list
     */
    public SensitiveWordFilter(List<String> list) {
        sensitiveWordMap = new SensitiveWordInit().getSensitiveWordToHashMap(list);
    }

    /**
     * 判断输入的内容是不是包含敏感词汇
     *
     * @param content:输入的内容
     * @param matchType:匹配规则
     * @return true or false
     */
    public boolean isContaintSensitiveWord(String content, int matchType) {
        boolean flag = false;

        for (int i = 0; i < content.length(); i++) {
            //循环匹配
            int matchFlag = CheckSensitiveWord(content, i, matchType);
            //大于0存在，返回true
            if (matchFlag > 0) {
                flag = true;
            }
        }

        return flag;
    }

    /**
     * 获取输入内容的敏感词
     *
     * @param content:输入内容
     * @param matchType:匹配类型
     * @return 匹配到的敏感词列表
     */
    public List<String> getSensitiveWord(String content, int matchType) {
        List<String> sensitiveWordList = new ArrayList<>();

        //判断是否存在敏感词汇，不存在为0
        int length = 0;
        for (int i = 0; i < content.length(); i++) {
            //判断是否包含敏感词汇
            length = CheckSensitiveWord(content, i, matchType);
            //如果存在
            if (length > 0) {
                //截取输入内容的i到i+length
                sensitiveWordList.add(content.substring(i, i + length));
                //减1的原因，是因为for会自增
                /**
                 * 举例：假设i从0开始,length=5，则匹配了0~4共5个字符
                 * 因此，下一次匹配时，i应该从5开始
                 * 注意：这一次匹配完了之后,会执行i++，因此i++的值应该是5
                 * 所以这里需要将i的值设成0+5-1=4
                 * 这一次执行完了后,i的值变成5
                 */
                i = i + length - 1;
            }
        }
        return sensitiveWordList;
    }

    /**
     * 替换敏感词汇字符
     *
     * @param content:输入的内容
     * @param matchType:匹配规则
     * @param replaceChar:替换字符，例如：*
     * @return 输入字符串，敏感词汇被替换成*
     */
    public String replaceSensitiveWord(String content, int matchType, String replaceChar) {
        String resultTxt = content;
        //获取所有的敏感词汇
        List<String> replaceSensitiveWordList = getSensitiveWord(content, matchType);
        //临时变量
        String word = null;
        //替换字符串
        String replaceString = null;
        //迭代器
        Iterator<String> it = replaceSensitiveWordList.iterator();
        while (it.hasNext()) {
            //敏感词汇(多个字符，假设5个字符)
            word = it.next();
            //这是替换后的字符(假设5个)
            replaceString = getReplaceChars(replaceChar, word.length());
            //替换后的字符串
            resultTxt = resultTxt.replaceAll(word, replaceString);
        }

        return resultTxt;
    }

    /**
     * 获取替换字符串
     *
     * @param replaceChar:替换成什么字符，例如：*
     * @param length:需要将几个字符替换成*
     * @return 多少个*
     */
    private String getReplaceChars(String replaceChar, int length) {
        String resultReplace = replaceChar;
        for (int i = 1; i < length; i++) {
            resultReplace += replaceChar;
        }
        return resultReplace;
    }

    /**
     * 检查输入内容是否包含敏感词汇
     *
     * @param content:输入内容
     * @param beginIndex:匹配位置
     * @param matchType:匹配规则
     * @return true or false
     */
    public int CheckSensitiveWord(String content, int beginIndex, int matchType) {

        //敏感词汇结束标识符，默认为没有匹配到
        boolean flag = false;
        //匹配到敏感词汇的次数
        int matchFlag = 0;
        //临时变量
        char word = 0;
        Map tmpMap = sensitiveWordMap;
        for (int i = beginIndex; i < content.length(); i++) {
            //取出输入内容的字符
            word = content.charAt(i);
            //获取key
            tmpMap = (Map) tmpMap.get(word);
            //如果存在
            if (tmpMap != null) {
                //匹配标识加1
                matchFlag++;
                //匹配到了最后，结束循环，返回匹配数
                if ("1".equals(tmpMap.get("isEnd"))) {
                    //结束标志位为true
                    flag = true;
                    //最小规则，退出for循环；最大规则，继续for循环
                    if (SensitiveWordFilter.minMatchTYpe == matchType) {
                        break;
                    }
                }
            } else {
                //不存在，直接退出for循环
                break;
            }
        }
        //词至少由两个字符组成
        //1.仅仅匹配到单个字符，它不能构成词，因此匹配失败
        //2.flag=false，说明匹配失败
        if (matchFlag < 2 || !flag) {
            matchFlag = 0;
        }
        return matchFlag;
    }


    /**
     * 匹配敏感词
     *
     * @param content           输入内容
     * @param sensitiveWordList 敏感词字符串集合
     * @return true 包含敏感词 false 不包含敏感词
     */
    public static Boolean containsSensitive(String content, List<String> sensitiveWordList) {
        for (String sensitiveWord : sensitiveWordList) {
            if (containsSensitive(content, sensitiveWord)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 匹配敏感词
     *
     * @param content       输入内容
     * @param sensitiveWord 敏感词字符串
     * @return true 包含敏感词 false 不包含敏感词
     */
    public static Boolean containsSensitive(String content, String sensitiveWord) {
        int m = 0;
        //去除特殊字符内容 其中的“（）”为特殊字符
        content = content.replaceAll(RegexUtils.SPECIAL_CHAR, "");
        String[] txtSplit = content.split("");
        for (int i = 0; i < txtSplit.length; i++) {
            if (sensitiveWord.contains(txtSplit[i])) {
                m++;
            }
        }
        return m == sensitiveWord.length();
    }

    //测试
//    public static void main(String[] args) {
//
//        String restrictWords = "场地、房、屋、金融、钢、铁、回收";
//        List<String> restrictWordsList = Arrays.asList(restrictWords.split("、")).stream().map(s -> String.format(s.trim())).collect(Collectors.toList());
//        System.out.println(SensitiveWordFilter.containsSensitive("场地", restrictWordsList));
//
//
//        List<String> list = new ArrayList<>();
//        list.add("张三");
//        list.add("李四");
//        list.add("王五");
//        list.add("赵六");
//        SensitiveWordFilter swf = new SensitiveWordFilter(list);
//        System.out.println("敏感词的数量：" + swf.sensitiveWordMap.size());
//        //输入字符串
//        String content = "张三";
//        //测试1:匹配输出所有的关键词(最小匹配规则)
//        List<String> list2 = swf.getSensitiveWord(content, 1);
//        System.out.println(list2);
//        //测试2:isContaintSensitiveWord
//        boolean exite = swf.isContaintSensitiveWord(content, 1);
//        System.out.println(exite);
//        //测试3：将敏感词汇替换成*
//        String replaceString = swf.replaceSensitiveWord(content, 1, "*");
//        System.out.println(replaceString);
//
//        System.out.println(SensitiveWordFilter.containsSensitive("张三", list));
//    }


}
